
// INCLUDES ********************************************************************

#include "BounceTween.h"

#include "Datatypes.h"

#include <iostream>



// NAMESPACES ******************************************************************

using namespace Meteor;

#pragma mark -
#pragma mark Constructor
// -----------------------------------------------------------------------------

BounceTween::BounceTween( const TweenAttribute attr, const EaseType type,
                          const float startValue, const float targetValue,
                          const float duration)

    : Tween( attr, type, startValue, targetValue, duration)
{

}

// -----------------------------------------------------------------------------

BounceTween::BounceTween( const TweenAttribute attr, const EaseType type,
                          const Vector2D& startValue, const Vector2D& targetValue,
                          const float duration)

    : Tween( attr, type, startValue, targetValue, duration)
{

}

#pragma mark -
#pragma mark Ease functions
// -----------------------------------------------------------------------------

const float BounceTween::None( const float time,
                               const float offset,
                               const float change,
                               const float duration)
{
    return time * ( change / duration) + offset;
}


// -----------------------------------------------------------------------------

const float BounceTween::In( const float time,
                             const float offset,
                             const float change,
                             const float duration)
{
    return time * ( change / duration) + offset;
}


// -----------------------------------------------------------------------------

const float BounceTween::Out( const float time,
                              const float offset,
                              const float change,
                              const float duration)
{
    float newTime = time;

    if ( ( newTime /= duration) < ( 1 / 2.75))
    {
        return change * ( 7.5625 * newTime * newTime) + offset;
    }
    else if ( newTime < ( 2 / 2.75))
    {
        return change*( 7.5625*( newTime -= ( 1.5 / 2.75)) * newTime + .75) + offset;
    }
    else if ( newTime < ( 2.5 / 2.75))
    {
        return change * ( 7.5625 * ( newTime -= ( 2.25 / 2.75)) * newTime + .9375) + offset;
    }
    else
    {
        return change * ( 7.5625 * ( newTime -= ( 2.625 / 2.75)) * newTime + .984375) + offset;
    }
}


// -----------------------------------------------------------------------------

const float BounceTween::InOut( const float time,
                                const float offset,
                                const float change,
                                const float duration)
{
    return time * ( change / duration) + offset;
}


// -----------------------------------------------------------------------------

const Vector2D BounceTween::Update( const float time)
{
    Vector2D returnValue;
    
    const float (BounceTween::*easeFunction)( const float, const float,
                                              const float, const float);
    
    switch ( mEaseType)
    {
        case Tween::EaseNone:
            easeFunction = &Tween::None;
            break;

        case Tween::EaseIn:
            easeFunction = &BounceTween::In;
            break;

        case Tween::EaseOut:
            easeFunction = &BounceTween::Out;
            break;
        
        case Tween::EaseInOut:
            easeFunction = &BounceTween::InOut;
            break;

        default:
            easeFunction = &Tween::None;
            break;
    }
    
    returnValue.SetX( ( this->*(easeFunction))( time, mStartValue.X(), mChange.X(), mDuration));
    
    if ( mAttribute == Position)
    {
        returnValue.SetY( ( this->*(easeFunction))( time, mStartValue.Y(), mChange.Y(), mDuration));

        Tween::IsFinished( returnValue);
    }
    else
    {
        Tween::IsFinished( returnValue.X());
    }
    
    return returnValue;
}